﻿namespace JavaScript8000.MagicBox
{
    using System;
    using System.Text;
    using System.Windows.Forms;

    using JavaScript8000.Common;
    using JavaScript8000.Parser;
    using JavaScript8000.Scaner;

    /// <summary>
    /// Represent magic box which execute JavaScript code.
    /// </summary>
    public class MagicBox
    {
        #region Constants and Fields

        /// <summary>
        /// All logs about magic process.
        /// </summary>
        private readonly StringBuilder logs;

        /// <summary>
        /// The tree of program.
        /// </summary>
        private readonly GrammarNode programmTree;

        /// <summary>
        /// User tokens.
        /// </summary>
        private readonly UserTokens userTokens;

        /// <summary>
        /// Tables which contains all user variables.
        /// </summary>
        private readonly VVarTable variables;

        /// <summary>
        /// Current node which we observe.
        /// </summary>
        private GrammarNode CurrentNode;

        /// <summary>
        /// Previous node which we observed.
        /// </summary>
        private GrammarNode PreviousNode;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="MagicBox"/> class.
        /// </summary>
        /// <param name="scanResults">
        /// The scan results.
        /// </param>
        /// <param name="tree">
        /// The tree.
        /// </param>
        public MagicBox(ScanResults scanResults, GrammarNode tree)
        {
            // Initialize variable table.
            this.variables = new VVarTable(scanResults);
            this.userTokens = scanResults.UserTokens;
            this.logs = new StringBuilder();
            this.programmTree = tree;

            // Assign parents for every node of tree;
            this.programmTree.MakeMeMom();
            this.CurrentNode = this.programmTree;
            this.PreviousNode = null;
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets a value indicating whether this instance is executed.
        /// </summary>
        /// <value>
        /// <c>true</c> if this instance is executed; otherwise, <c>false</c>.
        /// </value>
        public bool IsExecuted { get; private set; }

        /// <summary>
        /// Gets the logs about magic process.
        /// </summary>
        public string Logs
        {
            get
            {
                return this.logs.ToString();
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// Deinitializes this instance.
        /// </summary>
        public void Deinitialize()
        {
            if (this.PreviousNode != null)
            {
                int index = this.PreviousNode.Value.IndexOf(" [CURRENT NODE]");
                if (index >= 0)
                {
                    this.PreviousNode.Value =
                        this.PreviousNode.Value.Remove(this.PreviousNode.Value.IndexOf(" [CURRENT NODE]"));
                }
            }
        }

        /// <summary>
        /// Does the next step.
        /// </summary>
        /// <returns>
        /// Returns true if executing was fine; otherwise false.
        /// </returns>
        public bool DoStep()
        {
            this.logs.AppendLine(string.Format("Current node: {0}", this.CurrentNode.Value));

            // Mark current node and unmark previous.
            this.CurrentNode.Value = this.CurrentNode.Value + " [CURRENT NODE]";
            if (this.PreviousNode != null)
            {
                int index = this.PreviousNode.Value.IndexOf(" [CURRENT NODE]");
                if (index >= 0)
                {
                    this.PreviousNode.Value =
                        this.PreviousNode.Value.Remove(this.PreviousNode.Value.IndexOf(" [CURRENT NODE]"));
                }
            }

            GrammarNode badBoy = null;

            if (this.CurrentNode.Value == "IfStatement [CURRENT NODE]")
            {
                if (this.CurrentNode.Children[2].Token == null)
                {
                    badBoy = this.CurrentNode.Children[2];
                }
                else
                {
                    VVarValue expr =
                        this.GetTypedValue(
                            this.variables.GetVVar(this.CurrentNode.Children[2].Token.UserCode).Value,
                            VVarValue.VVarType.Bool);

                    if ((bool)expr.Value)
                    {
                        this.logs.AppendLine(string.Format("If expression is true."));
                        if (this.CurrentNode.Children[4].Token == null)
                        {
                            badBoy = this.CurrentNode.Children[4];
                        }
                    }
                    else
                    {
                        this.logs.AppendLine(string.Format("If expression is false."));
                        if (this.CurrentNode.Children.Count == 7)
                        {
                            // If 'else' part is exist.
                            if (this.CurrentNode.Children[6].Token == null)
                            {
                                badBoy = this.CurrentNode.Children[6];
                            }
                        }
                    }
                }
            }
            else if (this.CurrentNode.Value == "WhileStatement [CURRENT NODE]")
            {
                // WhileStatement = "while" "(" Expression ")" Statement ;
                if (this.CurrentNode.MySelfClone == null)
                {
                    // Create copy
                    this.CurrentNode.MySelfClone = (GrammarNode)this.CurrentNode.Clone();
                }

                if (this.CurrentNode.Children[2].Token == null)
                {
                    badBoy = this.CurrentNode.Children[2];
                }
                else
                {
                    VVarValue expr =
                        this.GetTypedValue(
                            this.variables.GetVVar(this.CurrentNode.Children[2].Token.UserCode).Value,
                            VVarValue.VVarType.Bool);

                    if ((bool)expr.Value)
                    {
                        if (this.CurrentNode.Children[4].Token == null)
                        {
                            badBoy = this.CurrentNode.Children[4];
                        }
                        else
                        {
                            if (this.CurrentNode.Children[2].Token.Code == SystemTokens.TempVar)
                            {
                                // Remove temp var.
                                this.variables.RemoveTempVar(this.CurrentNode.Children[2].Token.UserCode);
                            }

                            if (this.CurrentNode.Children[4].Token.Code == SystemTokens.TempVar)
                            {
                                // Remove temp var.
                                this.variables.RemoveTempVar(this.CurrentNode.Children[4].Token.UserCode);
                            }

                            // Next loop.
                            this.CurrentNode.Children[2] = (GrammarNode)this.CurrentNode.MySelfClone.Children[2].Clone();
                            this.CurrentNode.Children[4] = (GrammarNode)this.CurrentNode.MySelfClone.Children[4].Clone();
                            this.CurrentNode.Children[2].Parent = this.CurrentNode;
                            this.CurrentNode.Children[4].Parent = this.CurrentNode;

                            if (this.CurrentNode.Children[2].Token == null)
                            {
                                badBoy = this.CurrentNode.Children[2];
                            }
                            else
                            {
                                VVarValue expr2 = this.GetTypedValue(this.variables.GetVVar(this.CurrentNode.Children[2].Token.UserCode).Value, VVarValue.VVarType.Bool);
                                if ((bool)expr2.Value)
                                {
                                    if (this.CurrentNode.Children[4].Token == null)
                                    {
                                        badBoy = this.CurrentNode.Children[4];
                                    }
                                    else
                                    {
                                        this.logs.AppendLine(string.Format("Infinity loop is detected!"));
                                        return false;
                                    }
                                }
                                else
                                {
                                    throw new Exception("WTF?! Loop constant statement isn't constant!");
                                }
                            }
                        }
                    }
                    else
                    {
                        // Go out from loop.
                    }
                }
            }
            else if (this.CurrentNode.Value == "For2Statement [CURRENT NODE]")
            {
                // For2Statement = "for" "(" "var" VariableDeclarationList ";" Expression ";" Expression ")" Statement ;
                if (this.CurrentNode.MySelfClone == null)
                {
                    // Create copy
                    this.CurrentNode.MySelfClone = (GrammarNode)this.CurrentNode.Clone();
                }

                if (this.CurrentNode.Children[3].Token == null)
                {
                    badBoy = this.CurrentNode.Children[3];
                }
                else if (this.CurrentNode.Children[5].Token == null)
                {
                    badBoy = this.CurrentNode.Children[5];
                }
                else
                {
                    VVarValue expr =
                        this.GetTypedValue(
                            this.variables.GetVVar(this.CurrentNode.Children[5].Token.UserCode).Value,
                            VVarValue.VVarType.Bool);

                    if ((bool)expr.Value)
                    {
                        if (this.CurrentNode.Children[9].Token == null)
                        {
                            badBoy = this.CurrentNode.Children[9];
                        }
                        else if (this.CurrentNode.Children[7].Token == null)
                        {
                            badBoy = this.CurrentNode.Children[7];
                        }
                        else
                        {
                            if (this.CurrentNode.Children[5].Token.Code == SystemTokens.TempVar)
                            {
                                // Remove temp var.
                                this.variables.RemoveTempVar(this.CurrentNode.Children[5].Token.UserCode);
                            }

                            if (this.CurrentNode.Children[7].Token.Code == SystemTokens.TempVar)
                            {
                                // Remove temp var.
                                this.variables.RemoveTempVar(this.CurrentNode.Children[7].Token.UserCode);
                            }

                            if (this.CurrentNode.Children[9].Token.Code == SystemTokens.TempVar)
                            {
                                // Remove temp var.
                                this.variables.RemoveTempVar(this.CurrentNode.Children[9].Token.UserCode);
                            }

                            // Next loop.
                            this.CurrentNode.Children[5] = (GrammarNode)this.CurrentNode.MySelfClone.Children[5].Clone();
                            this.CurrentNode.Children[7] = (GrammarNode)this.CurrentNode.MySelfClone.Children[7].Clone();
                            this.CurrentNode.Children[9] = (GrammarNode)this.CurrentNode.MySelfClone.Children[9].Clone();
                            this.CurrentNode.Children[5].Parent = this.CurrentNode;
                            this.CurrentNode.Children[7].Parent = this.CurrentNode;
                            this.CurrentNode.Children[9].Parent = this.CurrentNode;

                            if (this.CurrentNode.Children[5].Token == null)
                            {
                                badBoy = this.CurrentNode.Children[5];
                            }
                            else
                            {
                                VVarValue expr2 = this.GetTypedValue(this.variables.GetVVar(this.CurrentNode.Children[5].Token.UserCode).Value, VVarValue.VVarType.Bool);
                                if ((bool)expr2.Value)
                                {
                                    if (this.CurrentNode.Children[9].Token == null)
                                    {
                                        badBoy = this.CurrentNode.Children[9];
                                    }
                                    else if (this.CurrentNode.Children[7].Token == null)
                                    {
                                        badBoy = this.CurrentNode.Children[7];
                                    }
                                    else
                                    {
                                        this.logs.AppendLine(string.Format("Infinity loop is detected!"));
                                        return false;
                                    }
                                }
                                else
                                {
                                    throw new Exception("WTF?! Loop constant statement isn't constant!");
                                }
                            }
                        }
                    }
                    else
                    {
                        // Go out from loop.
                    }
                }
            }
            else
            {
                badBoy = this.checkNode(this.CurrentNode);
            }

            if (badBoy != null)
            {
                this.logs.AppendLine(string.Format("We should execute some child nodes."));
                this.PreviousNode = this.CurrentNode;
                this.CurrentNode = badBoy;
            }
            else
            {
                this.logs.AppendLine(string.Format("Try to execute node..."));
                if (this.tryExecuteNode(this.CurrentNode))
                {
                    this.logs.AppendLine(string.Format("Success. Result code: {0}", this.CurrentNode.Token.UserCode));
                    this.PreviousNode = this.CurrentNode;
                    this.CurrentNode = this.CurrentNode.Parent;
                }
                else
                {
                    return false;
                }
            }

            return !this.IsExecuted;
        }

        /// <summary>
        /// The get tree.
        /// </summary>
        /// <returns>
        /// </returns>
        public TreeNode GetTree()
        {
            return this.ParseTree(this.programmTree);
        }

        /// <summary>
        /// Gets the variables list.
        /// </summary>
        /// <returns>
        /// String with variables.
        /// </returns>
        public string GetVariblesList()
        {
            return this.variables.ToString();
        }

        #endregion

        #region Methods

        /// <summary>
        /// The execute additive expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// The execute additive expression.
        /// </returns>
        /// <exception cref="InvalidOperationException">
        /// Occurs if node is not addictive expression.
        /// </exception>
        private VVarValue ExecuteAdditiveExpression(GrammarNode node)
        {
            // RULE:
            // AdditiveExpression = MultiplicativeExpression { AdditiveOperator MultiplicativeExpression } ;
            // AdditiveOperator = "+" | "-" ;
            if (node.Children.Count == 0 || node.Children.Count % 2 == 0)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            var result = new VVarValue(this.variables.GetVVar(node.Children[0].Token.UserCode).Value);

            if (node.Children[0].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[0].Token.UserCode);
            }

            if (result.Type != VVarValue.VVarType.Decimal && result.Type != VVarValue.VVarType.String)
            {
                throw new Exception(
                    string.Format(
                        "Wrong variable type for addiction expression. Variable: {0} with code: {1}",
                        this.variables.GetVVar(node.Children[0].Token.UserCode).Name,
                        node.Children[0].Token.UserCode));
            }

            VVar tempVar;
            int i = 2;

            // If false - subtract.
            bool sum;

            while (i < node.Children.Count)
            {
                sum = node.Children[i - 1].Token.Code == SystemTokens.GetCode("+");
                if (!sum && node.Children[i - 1].Token.Code != SystemTokens.GetCode("-"))
                {
                    throw new Exception(
                        string.Format("Wrong addiction operation with code {0}", node.Children[i - 1].Token.Code));
                }

                tempVar = this.variables.GetVVar(node.Children[i].Token.UserCode);

                if (node.Children[i].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[i].Token.UserCode);
                }

                if (sum)
                {
                    if (result.Type == VVarValue.VVarType.String || tempVar.Value.Type == VVarValue.VVarType.String)
                    {
                        string s1 = result.Value.ToString();
                        string s2 = tempVar.Value.Value.ToString();
                        result.Value = s1 + s2;
                        result.Type = VVarValue.VVarType.String;
                    }
                    else if (tempVar.Value.Type == VVarValue.VVarType.Decimal)
                    {
                        var s1 = (decimal)result.Value;
                        var s2 = (decimal)tempVar.Value.Value;
                        result.Value = s1 + s2;
                    }
                    else
                    {
                        throw new Exception(
                            string.Format(
                                "Wrong variable type for addiction expression. Variable: {0} with code: {1}",
                                this.variables.GetVVar(node.Children[i].Token.UserCode).Name,
                                node.Children[i].Token.UserCode));
                    }
                }
                else
                {
                    decimal s1;
                    decimal s2;

                    if (result.Type == VVarValue.VVarType.String)
                    {
                        s1 = decimal.Parse((string)result.Value);
                    }
                    else
                    {
                        s1 = (decimal)result.Value;
                    }

                    if (tempVar.Value.Type == VVarValue.VVarType.String)
                    {
                        s2 = decimal.Parse((string)tempVar.Value.Value);
                    }
                    else if (tempVar.Value.Type != VVarValue.VVarType.Decimal)
                    {
                        throw new Exception(
                            string.Format(
                                "Wrong variable type for addiction expression. Variable: {0} with code: {1}",
                                this.variables.GetVVar(node.Children[i].Token.UserCode).Name,
                                node.Children[i].Token.UserCode));
                    }
                    else
                    {
                        s2 = (decimal)tempVar.Value.Value;
                    }

                    result.Value = s1 - s2;
                    result.Type = VVarValue.VVarType.Decimal;
                }

                i += 2;
            }

            return result;
        }

        /// <summary>
        /// Executes the assignment expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// Result of assignment.
        /// </returns>
        private VVarValue ExecuteAssignmentExpression(GrammarNode node)
        {
            // RULE:
            // AssignmentExpression = LeftHandSideExpression AssignmentOperator AssignmentExpression | ConditionalExpression ;
            // AssignmentExpressionNoIn = LeftHandSideExpression AssignmentOperator AssignmentExpressionNoIn | ConditionalExpressionNoIn ;
            // AssignmentOperator = "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | ">>>=" | "&=" | "^=" | "|=";

            if (node.Children.Count == 3)
            {
                // Get value.
                var value = new VVarValue(this.variables.GetVVar(node.Children[2].Token.UserCode).Value);
                if (node.Children[2].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[2].Token.UserCode);
                }

                // Check that variable may be assigned.
                VVar vvar = this.variables.GetVVar(node.Children[0].Token.UserCode);

                if (!vvar.Assignable)
                {
                    throw new Exception(string.Format("Variable {0} can't be assigned.", vvar.Name));
                }

                // Switch operator.
                int operatorCode = node.Children[1].Token.Code;

                if (operatorCode == SystemTokens.GetCode("="))
                {
                    vvar.Value = value;
                }
                else if (operatorCode == SystemTokens.GetCode("*="))
                {
                    decimal s1, s2;
                    if (value.Type == VVarValue.VVarType.Decimal)
                    {
                        s2 = (decimal)value.Value;
                    }
                    else if (value.Type == VVarValue.VVarType.String)
                    {
                        s2 = decimal.Parse(value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    if (vvar.Value.Type == VVarValue.VVarType.Decimal)
                    {
                        s1 = (decimal)vvar.Value.Value;
                    }
                    else if (vvar.Value.Type == VVarValue.VVarType.String)
                    {
                        s1 = decimal.Parse(vvar.Value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    vvar.Value = new VVarValue { Type = VVarValue.VVarType.Decimal, Value = s1 * s2 };
                }
                else if (operatorCode == SystemTokens.GetCode("/="))
                {
                    decimal s1, s2;
                    if (value.Type == VVarValue.VVarType.Decimal)
                    {
                        s2 = (decimal)value.Value;
                    }
                    else if (value.Type == VVarValue.VVarType.String)
                    {
                        s2 = decimal.Parse(value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    if (vvar.Value.Type == VVarValue.VVarType.Decimal)
                    {
                        s1 = (decimal)vvar.Value.Value;
                    }
                    else if (vvar.Value.Type == VVarValue.VVarType.String)
                    {
                        s1 = decimal.Parse(vvar.Value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    vvar.Value = new VVarValue { Type = VVarValue.VVarType.Decimal, Value = s1 / s2 };
                }
                else if (operatorCode == SystemTokens.GetCode("%="))
                {
                    decimal s1, s2;
                    if (value.Type == VVarValue.VVarType.Decimal)
                    {
                        s2 = (decimal)value.Value;
                    }
                    else if (value.Type == VVarValue.VVarType.String)
                    {
                        s2 = decimal.Parse(value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    if (vvar.Value.Type == VVarValue.VVarType.Decimal)
                    {
                        s1 = (decimal)vvar.Value.Value;
                    }
                    else if (vvar.Value.Type == VVarValue.VVarType.String)
                    {
                        s1 = decimal.Parse(vvar.Value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    vvar.Value = new VVarValue { Type = VVarValue.VVarType.Decimal, Value = s1 % s2 };
                }
                else if (operatorCode == SystemTokens.GetCode("+="))
                {
                    if (value.Type == VVarValue.VVarType.String)
                    {
                        string s1, s2;
                        s2 = value.Value.ToString();
                        if (vvar.Value.Type == VVarValue.VVarType.Decimal
                            || vvar.Value.Type == VVarValue.VVarType.String)
                        {
                            s1 = vvar.Value.Value.ToString();
                        }
                        else
                        {
                            throw new Exception("Wrong operand type.");
                        }

                        vvar.Value = new VVarValue { Type = VVarValue.VVarType.String, Value = s1 + s2 };
                    }
                    else if (value.Type == VVarValue.VVarType.Decimal)
                    {
                        if (vvar.Value.Type == VVarValue.VVarType.Decimal)
                        {
                            var s1 = (decimal)vvar.Value.Value;
                            var s2 = (decimal)value.Value;

                            vvar.Value = new VVarValue { Type = VVarValue.VVarType.Decimal, Value = s1 + s2 };
                        }
                        else if (vvar.Value.Type == VVarValue.VVarType.String)
                        {
                            string s1 = vvar.Value.Value.ToString();
                            string s2 = value.Value.ToString();

                            vvar.Value = new VVarValue { Type = VVarValue.VVarType.String, Value = s1 + s2 };
                        }
                        else
                        {
                            throw new Exception("Wrong operand type.");
                        }
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }
                }
                else if (operatorCode == SystemTokens.GetCode("-="))
                {
                    decimal s1, s2;
                    if (value.Type == VVarValue.VVarType.Decimal)
                    {
                        s2 = (decimal)value.Value;
                    }
                    else if (value.Type == VVarValue.VVarType.String)
                    {
                        s2 = decimal.Parse(value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    if (vvar.Value.Type == VVarValue.VVarType.Decimal)
                    {
                        s1 = (decimal)vvar.Value.Value;
                    }
                    else if (vvar.Value.Type == VVarValue.VVarType.String)
                    {
                        s1 = decimal.Parse(vvar.Value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    vvar.Value = new VVarValue { Type = VVarValue.VVarType.Decimal, Value = s1 - s2 };
                }
                else if (operatorCode == SystemTokens.GetCode("<<="))
                {
                    decimal s1, s2;
                    if (value.Type == VVarValue.VVarType.Decimal)
                    {
                        s2 = (decimal)value.Value;
                    }
                    else if (value.Type == VVarValue.VVarType.String)
                    {
                        s2 = decimal.Parse(value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    if (vvar.Value.Type == VVarValue.VVarType.Decimal)
                    {
                        s1 = (decimal)vvar.Value.Value;
                    }
                    else if (vvar.Value.Type == VVarValue.VVarType.String)
                    {
                        s1 = decimal.Parse(vvar.Value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    vvar.Value = new VVarValue { Type = VVarValue.VVarType.Decimal, Value = (int)s1 << (int)s2 };
                }
                else if (operatorCode == SystemTokens.GetCode(">>="))
                {
                    decimal s1, s2;
                    if (value.Type == VVarValue.VVarType.Decimal)
                    {
                        s2 = (decimal)value.Value;
                    }
                    else if (value.Type == VVarValue.VVarType.String)
                    {
                        s2 = decimal.Parse(value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    if (vvar.Value.Type == VVarValue.VVarType.Decimal)
                    {
                        s1 = (decimal)vvar.Value.Value;
                    }
                    else if (vvar.Value.Type == VVarValue.VVarType.String)
                    {
                        s1 = decimal.Parse(vvar.Value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    vvar.Value = new VVarValue { Type = VVarValue.VVarType.Decimal, Value = (int)s1 >> (int)s2 };
                }
                else if (operatorCode == SystemTokens.GetCode(">>>="))
                {
                    throw new NotImplementedException("this operator isn't implemented yet.");
                }
                else if (operatorCode == SystemTokens.GetCode("&="))
                {
                    decimal s1, s2;
                    if (value.Type == VVarValue.VVarType.Decimal)
                    {
                        s2 = (decimal)value.Value;
                    }
                    else if (value.Type == VVarValue.VVarType.String)
                    {
                        s2 = decimal.Parse(value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    if (vvar.Value.Type == VVarValue.VVarType.Decimal)
                    {
                        s1 = (decimal)vvar.Value.Value;
                    }
                    else if (vvar.Value.Type == VVarValue.VVarType.String)
                    {
                        s1 = decimal.Parse(vvar.Value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    vvar.Value = new VVarValue { Type = VVarValue.VVarType.Decimal, Value = (int)s1 & (int)s2 };
                }
                else if (operatorCode == SystemTokens.GetCode("^="))
                {
                    decimal s1, s2;
                    if (value.Type == VVarValue.VVarType.Decimal)
                    {
                        s2 = (decimal)value.Value;
                    }
                    else if (value.Type == VVarValue.VVarType.String)
                    {
                        s2 = decimal.Parse(value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    if (vvar.Value.Type == VVarValue.VVarType.Decimal)
                    {
                        s1 = (decimal)vvar.Value.Value;
                    }
                    else if (vvar.Value.Type == VVarValue.VVarType.String)
                    {
                        s1 = decimal.Parse(vvar.Value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    vvar.Value = new VVarValue { Type = VVarValue.VVarType.Decimal, Value = (int)s1 ^ (int)s2 };
                }
                else if (operatorCode == SystemTokens.GetCode("|="))
                {
                    decimal s1, s2;
                    if (value.Type == VVarValue.VVarType.Decimal)
                    {
                        s2 = (decimal)value.Value;
                    }
                    else if (value.Type == VVarValue.VVarType.String)
                    {
                        s2 = decimal.Parse(value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    if (vvar.Value.Type == VVarValue.VVarType.Decimal)
                    {
                        s1 = (decimal)vvar.Value.Value;
                    }
                    else if (vvar.Value.Type == VVarValue.VVarType.String)
                    {
                        s1 = decimal.Parse(vvar.Value.Value.ToString());
                    }
                    else
                    {
                        throw new Exception("Wrong operand type.");
                    }

                    vvar.Value = new VVarValue { Type = VVarValue.VVarType.Decimal, Value = (int)s1 | (int)s2 };
                }
                else
                {
                    throw new Exception("Wrong assign operator.");
                }

                return vvar.Value;
            }

            if (node.Children.Count == 1)
            {
                // Just return result.
                var result = new VVarValue(this.variables.GetVVar(node.Children[0].Token.UserCode).Value);
                if (node.Children[0].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[0].Token.UserCode);
                }

                return result;
            }

            throw new InvalidOperationException("Wrong param node.");
        }

        /// <summary>
        /// Executes the bitwise expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// </returns>
        private VVarValue ExecuteBitwiseExpression(GrammarNode node)
        {
            // RULE:
            // BitwiseANDExpression = EqualityExpression { BitwiseANDOperator EqualityExpression } ;
            // BitwiseANDExpressionNoIn = EqualityExpressionNoIn { BitwiseANDOperator EqualityExpressionNoIn } ;
            // BitwiseANDOperator = "&" ;
            // BitwiseXORExpression = BitwiseANDExpression { BitwiseXOROperator BitwiseANDExpression } ;
            // BitwiseXORExpressionNoIn = BitwiseANDExpressionNoIn { BitwiseXOROperator BitwiseANDExpressionNoIn } ;
            // BitwiseXOROperator = "^" ;
            // BitwiseORExpression = BitwiseXORExpression { BitwiseOROperator BitwiseXORExpression } ;
            // BitwiseORExpressionNoIn = BitwiseXORExpressionNoIn { BitwiseOROperator BitwiseXORExpressionNoIn } ;
            // BitwiseOROperator = "|" ;
            if (node.Children.Count == 0 || node.Children.Count % 2 == 0)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            var result = new VVarValue(this.variables.GetVVar(node.Children[0].Token.UserCode).Value);

            if (node.Children[0].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[0].Token.UserCode);
            }

            if (result.Type != VVarValue.VVarType.Decimal)
            {
                if (result.Type != VVarValue.VVarType.String)
                {
                    throw new Exception(
                        string.Format(
                            "Wrong variable type for bitwise expression. Variable: {0} with code: {1}",
                            this.variables.GetVVar(node.Children[0].Token.UserCode).Name,
                            node.Children[0].Token.UserCode));
                }
                else
                {
                    result.Type = VVarValue.VVarType.Decimal;
                    result.Value = decimal.Parse((string)result.Value);
                }
            }

            VVar tempVar;
            int i = 2;

            while (i < node.Children.Count)
            {
                tempVar = this.variables.GetVVar(node.Children[i].Token.UserCode);

                if (node.Children[i].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[i].Token.UserCode);
                }

                switch (tempVar.Value.Type)
                {
                    case VVarValue.VVarType.Decimal:
                        break;
                    case VVarValue.VVarType.String:
                        tempVar.Value.Value = decimal.Parse((string)tempVar.Value.Value);
                        tempVar.Value.Type = VVarValue.VVarType.Decimal;
                        break;
                    default:
                        throw new Exception(
                            string.Format(
                                "Wrong variable type for multiplicative expression. Variable: {0} with code: {1}",
                                this.variables.GetVVar(node.Children[i].Token.UserCode).Name,
                                node.Children[i].Token.UserCode));
                }

                int operatorCode = node.Children[i - 1].Token.Code;
                if (operatorCode == SystemTokens.GetCode("&"))
                {
                    result.Value = (decimal)(((long)result.Value) & ((long)tempVar.Value.Value));
                }
                else if (operatorCode == SystemTokens.GetCode("|"))
                {
                    result.Value = (decimal)(((long)result.Value) | ((long)tempVar.Value.Value));
                }
                else if (operatorCode == SystemTokens.GetCode("^"))
                {
                    result.Value = (decimal)(((long)result.Value) ^ ((long)tempVar.Value.Value));
                }
                else
                {
                    throw new Exception(
                        string.Format("Wrong bitwise operation with code {0}", node.Children[i - 1].Token.Code));
                }

                i += 2;
            }

            return result;
        }

        /// <summary>
        /// Executes the block expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// </returns>
        private VVarValue ExecuteBlockExpression(GrammarNode node)
        {
            // RULE:
            // Block = "{" [ StatementList ] "}" ;
            if (node.Children.Count != 2 && node.Children.Count != 3)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            if (node.Children.Count == 2)
            {
                return new VVarValue { Type = VVarValue.VVarType.Unknown };
            }

            var result = new VVarValue(this.variables.GetVVar(node.Children[1].Token.UserCode).Value);
            if (node.Children[1].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[1].Token.UserCode);
            }

            return result;
        }

        /// <summary>
        /// Executes the conditional expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// </returns>
        private VVarValue ExecuteConditionalExpression(GrammarNode node)
        {
            // RULE:
            // ConditionalExpression = LogicalORExpression [ "?" AssignmentExpression ":" AssignmentExpression ] ;
            // ConditionalExpressionNoIn = LogicalORExpressionNoIn [ "?" AssignmentExpression ":" AssignmentExpressionNoIn ] ;

            if (node.Children.Count == 1)
            {
                var result = new VVarValue(this.variables.GetVVar(node.Children[0].Token.UserCode).Value);
                if (node.Children[0].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[0].Token.UserCode);
                }

                return result;
            }

            if (node.Children.Count == 5)
            {
                VVarValue condition = this.GetTypedValue(
                    this.variables.GetVVar(node.Children[0].Token.UserCode).Value, VVarValue.VVarType.Bool);
                if (node.Children[0].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[0].Token.UserCode);
                }

                // Check tokens.
                if (node.Children[1].Token.Code != SystemTokens.GetCode("?")
                    || node.Children[3].Token.Code != SystemTokens.GetCode(":"))
                {
                    throw new Exception("Wrong tokens in conditional expression.");
                }

                var a = new VVarValue(this.variables.GetVVar(node.Children[2].Token.UserCode).Value);
                if (node.Children[2].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[2].Token.UserCode);
                }

                var b = new VVarValue(this.variables.GetVVar(node.Children[2].Token.UserCode).Value);
                if (node.Children[4].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[4].Token.UserCode);
                }

                return (bool)condition.Value ? a : b;
            }

            throw new InvalidOperationException("Wrong param node.");
        }

        /// <summary>
        /// Executes the empty statement expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// </returns>
        private VVarValue ExecuteEmptyStatementExpression(GrammarNode node)
        {
            // RULE:
            // EmptyStatement = ";";
            if (node.Children.Count != 1)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            return new VVarValue { Type = VVarValue.VVarType.Unknown };
        }

        /// <summary>
        /// Executes the equality expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// </returns>
        private VVarValue ExecuteEqualityExpression(GrammarNode node)
        {
            // RULE:
            // EqualityExpression = RelationalExpression { EqualityOperator RelationalExpression } ;
            // EqualityExpressionNoIn = RelationalExpressionNoIn { EqualityOperator RelationalExpressionNoIn } ;
            // EqualityOperator = "==" | "!=" | "===" | "!==" ;
            if (node.Children.Count == 0 || node.Children.Count % 2 == 0)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            var result = new VVarValue(this.variables.GetVVar(node.Children[0].Token.UserCode).Value);

            if (node.Children[0].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[0].Token.UserCode);
            }

            VVarValue tempVarValue;
            int i = 2;

            while (i < node.Children.Count)
            {
                tempVarValue = new VVarValue(this.variables.GetVVar(node.Children[i].Token.UserCode).Value);

                if (node.Children[i].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[i].Token.UserCode);
                }

                int operatorCode = node.Children[i - 1].Token.Code;

                if (operatorCode == SystemTokens.GetCode("==="))
                {
                    if (result.Type != tempVarValue.Type)
                    {
                        result = new VVarValue { Type = VVarValue.VVarType.Bool, Value = false };
                    }
                    else
                    {
                        switch (result.Type)
                        {
                            case VVarValue.VVarType.Decimal:
                                result = new VVarValue
                                    {
                                        Type = VVarValue.VVarType.Bool,
                                        Value = (decimal)result.Value == (decimal)tempVarValue.Value
                                    };
                                break;
                            case VVarValue.VVarType.String:
                                result = new VVarValue
                                    {
                                        Type = VVarValue.VVarType.Bool,
                                        Value =
                                            string.CompareOrdinal((string)result.Value, (string)tempVarValue.Value) == 0
                                    };
                                break;
                            case VVarValue.VVarType.Bool:
                                result = new VVarValue
                                    {
                                        Type = VVarValue.VVarType.Bool,
                                        Value = (bool)result.Value == (bool)tempVarValue.Value
                                    };
                                break;
                            case VVarValue.VVarType.Object:
                                throw new NotImplementedException("Object equality isn't implemented yet.");
                                break;
                            case VVarValue.VVarType.Function:
                                throw new NotImplementedException("Function equality isn't implemented yet.");
                                break;
                            case VVarValue.VVarType.Array:
                                throw new NotImplementedException("Array equality isn't implemented yet.");
                                break;
                            case VVarValue.VVarType.Unknown:
                                result = new VVarValue { Type = VVarValue.VVarType.Bool, Value = false };
                                break;
                            default:
                                throw new NotImplementedException("New type?!.");
                                break;
                        }
                    }
                }
                else if (operatorCode == SystemTokens.GetCode("!=="))
                {
                    if (result.Type != tempVarValue.Type)
                    {
                        result = new VVarValue { Type = VVarValue.VVarType.Bool, Value = true };
                    }
                    else
                    {
                        switch (result.Type)
                        {
                            case VVarValue.VVarType.Decimal:
                                result = new VVarValue
                                    {
                                        Type = VVarValue.VVarType.Bool,
                                        Value = (decimal)result.Value != (decimal)tempVarValue.Value
                                    };
                                break;
                            case VVarValue.VVarType.String:
                                result = new VVarValue
                                    {
                                        Type = VVarValue.VVarType.Bool,
                                        Value =
                                            string.CompareOrdinal((string)result.Value, (string)tempVarValue.Value) != 0
                                    };
                                break;
                            case VVarValue.VVarType.Bool:
                                result = new VVarValue
                                    {
                                        Type = VVarValue.VVarType.Bool,
                                        Value = (bool)result.Value != (bool)tempVarValue.Value
                                    };
                                break;
                            case VVarValue.VVarType.Object:
                                throw new NotImplementedException("Object equality isn't implemented yet.");
                                break;
                            case VVarValue.VVarType.Function:
                                throw new NotImplementedException("Function equality isn't implemented yet.");
                                break;
                            case VVarValue.VVarType.Array:
                                throw new NotImplementedException("Array equality isn't implemented yet.");
                                break;
                            case VVarValue.VVarType.Unknown:
                                result = new VVarValue { Type = VVarValue.VVarType.Bool, Value = true };
                                break;
                            default:
                                throw new NotImplementedException("New type?!.");
                                break;
                        }
                    }
                }
                else if (operatorCode == SystemTokens.GetCode("=="))
                {
                    if (result.Type != tempVarValue.Type)
                    {
                        if (result.Type == VVarValue.VVarType.Unknown || tempVarValue.Type == VVarValue.VVarType.Unknown)
                        {
                            result = new VVarValue { Type = VVarValue.VVarType.Bool, Value = false };
                        }
                        else
                        {
                            result.Type = VVarValue.VVarType.Bool;
                            result.Value = result.Value.ToString() == tempVarValue.Value.ToString();
                        }
                    }
                    else
                    {
                        switch (result.Type)
                        {
                            case VVarValue.VVarType.Decimal:
                                result = new VVarValue
                                    {
                                        Type = VVarValue.VVarType.Bool,
                                        Value = (decimal)result.Value == (decimal)tempVarValue.Value
                                    };
                                break;
                            case VVarValue.VVarType.String:
                                result = new VVarValue
                                    {
                                        Type = VVarValue.VVarType.Bool,
                                        Value =
                                            string.CompareOrdinal((string)result.Value, (string)tempVarValue.Value) == 0
                                    };
                                break;
                            case VVarValue.VVarType.Bool:
                                result = new VVarValue
                                    {
                                        Type = VVarValue.VVarType.Bool,
                                        Value = (bool)result.Value == (bool)tempVarValue.Value
                                    };
                                break;
                            case VVarValue.VVarType.Object:
                                throw new NotImplementedException("Object equality isn't implemented yet.");
                                break;
                            case VVarValue.VVarType.Function:
                                throw new NotImplementedException("Function equality isn't implemented yet.");
                                break;
                            case VVarValue.VVarType.Array:
                                throw new NotImplementedException("Array equality isn't implemented yet.");
                                break;
                            case VVarValue.VVarType.Unknown:
                                result = new VVarValue { Type = VVarValue.VVarType.Bool, Value = false };
                                break;
                            default:
                                throw new NotImplementedException("New type?!.");
                                break;
                        }
                    }
                }
                else if (operatorCode == SystemTokens.GetCode("!="))
                {
                    if (result.Type != tempVarValue.Type)
                    {
                        if (result.Type == VVarValue.VVarType.Unknown || tempVarValue.Type == VVarValue.VVarType.Unknown)
                        {
                            result = new VVarValue { Type = VVarValue.VVarType.Bool, Value = true };
                        }
                        else
                        {
                            result.Type = VVarValue.VVarType.Bool;
                            result.Value = result.Value.ToString() != tempVarValue.Value.ToString();
                        }
                    }
                    else
                    {
                        switch (result.Type)
                        {
                            case VVarValue.VVarType.Decimal:
                                result = new VVarValue
                                    {
                                        Type = VVarValue.VVarType.Bool,
                                        Value = (decimal)result.Value != (decimal)tempVarValue.Value
                                    };
                                break;
                            case VVarValue.VVarType.String:
                                result = new VVarValue
                                    {
                                        Type = VVarValue.VVarType.Bool,
                                        Value =
                                            string.CompareOrdinal((string)result.Value, (string)tempVarValue.Value) != 0
                                    };
                                break;
                            case VVarValue.VVarType.Bool:
                                result = new VVarValue
                                    {
                                        Type = VVarValue.VVarType.Bool,
                                        Value = (bool)result.Value != (bool)tempVarValue.Value
                                    };
                                break;
                            case VVarValue.VVarType.Object:
                                throw new NotImplementedException("Object equality isn't implemented yet.");
                                break;
                            case VVarValue.VVarType.Function:
                                throw new NotImplementedException("Function equality isn't implemented yet.");
                                break;
                            case VVarValue.VVarType.Array:
                                throw new NotImplementedException("Array equality isn't implemented yet.");
                                break;
                            case VVarValue.VVarType.Unknown:
                                result = new VVarValue { Type = VVarValue.VVarType.Bool, Value = true };
                                break;
                            default:
                                throw new NotImplementedException("New type?!.");
                                break;
                        }
                    }
                }

                i += 2;
            }

            return result;
        }

        /// <summary>
        /// Executes the expression expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// </returns>
        private VVarValue ExecuteExpressionExpression(GrammarNode node)
        {
            // RULE:
            // Expression = AssignmentExpression { "," AssignmentExpression } ;
            // ExpressionNoIn = AssignmentExpressionNoIn { "," AssignmentExpressionNoIn } ;
            if (node.Children.Count % 2 == 0)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            int i = 0;
            VVarValue result = null;

            while (i < node.Children.Count)
            {
                result = new VVarValue(this.variables.GetVVar(node.Children[i].Token.UserCode).Value);
                if (node.Children[i].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[i].Token.UserCode);
                }

                i += 2;
            }

            return result;
        }

        /// <summary>
        /// Executes the expression statement expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// Value of expression.
        /// </returns>
        private VVarValue ExecuteExpressionStatementExpression(GrammarNode node)
        {
            if (node.Children.Count != 2)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            var result = new VVarValue(this.variables.GetVVar(node.Children[0].Token.UserCode).Value);
            if (node.Children[0].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[0].Token.UserCode);
            }

            if (node.Children[1].Token.Code != SystemTokens.GetCode(";"))
            {
                throw new Exception("Wrong end of expression.");
            }

            return result;
        }

        /// <summary>
        /// Executes if statement expresion.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// </returns>
        private VVarValue ExecuteIfStatementExpresion(GrammarNode node)
        {
            // RULE:
            // IfStatement = "if" "(" Expression ")" Statement [ "else" Statement ] ;
            if (node.Children.Count != 5 && node.Children.Count != 7)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            VVarValue expr = this.GetTypedValue(
                this.variables.GetVVar(node.Children[2].Token.UserCode).Value, VVarValue.VVarType.Bool);
            if (node.Children[2].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[2].Token.UserCode);
            }

            VVarValue result;

            if ((bool)expr.Value)
            {
                result = new VVarValue(this.variables.GetVVar(node.Children[4].Token.UserCode).Value);
                if (node.Children[4].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[4].Token.UserCode);
                }
            }
            else if (node.Children.Count == 7)
            {
                // Else part is exist.
                result = new VVarValue(this.variables.GetVVar(node.Children[6].Token.UserCode).Value);
                if (node.Children[6].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[6].Token.UserCode);
                }
            }
            else
            {
                result = new VVarValue { Type = VVarValue.VVarType.Unknown };
            }

            return result;
        }

        /// <summary>
        /// Executes the initialiser expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// Initialize value.
        /// </returns>
        private VVarValue ExecuteInitialiserExpression(GrammarNode node)
        {
            // Rule:
            // Initialiser = "=" AssignmentExpression ;
            // InitialiserNoIn = "=" AssignmentExpressionNoIn ;
            if (node.Children.Count != 2)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            if (node.Children[0].Token.Code != SystemTokens.GetCode("="))
            {
                throw new Exception("Wrong assign operator in variable declaration.");
            }

            var result = new VVarValue(this.variables.GetVVar(node.Children[1].Token.UserCode).Value);
            if (node.Children[1].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[1].Token.UserCode);
            }

            return result;
        }

        /// <summary>
        /// Executes the source elements expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// Last value.
        /// </returns>
        private VVarValue ExecuteListExpression(GrammarNode node)
        {
            // RULE:
            // SourceElements = SourceElement { SourceElement } ;
            // StatementList = Statement { Statement } ;
            if (node.Children.Count < 1)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            int i = 0;
            VVarValue result = null;

            while (i < node.Children.Count)
            {
                result = new VVarValue(this.variables.GetVVar(node.Children[i].Token.UserCode).Value);
                if (node.Children[i].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[i].Token.UserCode);
                }

                i++;
            }

            return result;
        }

        /// <summary>
        /// Executes the logical expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// </returns>
        private VVarValue ExecuteLogicalExpression(GrammarNode node)
        {
            // RULE:
            // LogicalANDExpression = BitwiseORExpression { LogicalANDOperator BitwiseORExpression } ;
            // LogicalANDExpressionNoIn = BitwiseORExpressionNoIn { LogicalANDOperator BitwiseORExpressionNoIn } ;
            // LogicalANDOperator = "&&" ;
            // LogicalORExpression = LogicalANDExpression { LogicalOROperator LogicalANDExpression } ;
            // LogicalORExpressionNoIn = LogicalANDExpressionNoIn { LogicalOROperator LogicalANDExpressionNoIn } ;
            // LogicalOROperator = "||" ;
            if (node.Children.Count == 0 || node.Children.Count % 2 == 0)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            var result = new VVarValue(this.variables.GetVVar(node.Children[0].Token.UserCode).Value);

            if (node.Children[0].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[0].Token.UserCode);
            }

            result = this.GetTypedValue(result, VVarValue.VVarType.Bool);

            VVarValue tempVarValue;
            int i = 2;

            while (i < node.Children.Count)
            {
                tempVarValue = new VVarValue(this.variables.GetVVar(node.Children[i].Token.UserCode).Value);

                if (node.Children[i].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[i].Token.UserCode);
                }

                switch (tempVarValue.Type)
                {
                    case VVarValue.VVarType.Decimal:
                        tempVarValue.Value = (decimal)tempVarValue.Value != 0;
                        break;
                    case VVarValue.VVarType.Unknown:
                        tempVarValue.Value = false;
                        break;
                    case VVarValue.VVarType.String:
                        tempVarValue.Value = !string.IsNullOrEmpty((string)tempVarValue.Value);
                        break;
                    case VVarValue.VVarType.Array:
                        tempVarValue.Value = ((object[])tempVarValue.Value).Length == 0;
                        break;
                    case VVarValue.VVarType.Function:
                        throw new NotImplementedException("function is not implemented yet");
                        break;
                    case VVarValue.VVarType.Object:
                        tempVarValue.Value = tempVarValue.Value != null;
                        break;
                }

                tempVarValue.Type = VVarValue.VVarType.Bool;

                int operatorCode = node.Children[i - 1].Token.Code;
                if (operatorCode == SystemTokens.GetCode("&&"))
                {
                    result.Value = ((bool)result.Value) && ((bool)tempVarValue.Value);
                }
                else if (operatorCode == SystemTokens.GetCode("||"))
                {
                    result.Value = ((bool)result.Value) || ((bool)tempVarValue.Value);
                }
                else
                {
                    throw new Exception(
                        string.Format("Wrong logical operation with code {0}", node.Children[i - 1].Token.Code));
                }

                i += 2;
            }

            return result;
        }

        /// <summary>
        /// Executes the multiplicative expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// Result of multiplicative operation.
        /// </returns>
        private VVarValue ExecuteMultiplicativeExpression(GrammarNode node)
        {
            // RULE:
            // MultiplicativeExpression = UnaryExpression { MultiplicativeOperator UnaryExpression } ;
            // MultiplicativeOperator = "*" | "/" | "%" ;
            if (node.Children.Count == 0 || node.Children.Count % 2 == 0)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            var result = new VVarValue(this.variables.GetVVar(node.Children[0].Token.UserCode).Value);

            if (node.Children[0].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[0].Token.UserCode);
            }

            if (result.Type != VVarValue.VVarType.Decimal)
            {
                if (result.Type != VVarValue.VVarType.String)
                {
                    throw new Exception(
                        string.Format(
                            "Wrong variable type for multiplicative expression. Variable: {0} with code: {1}",
                            this.variables.GetVVar(node.Children[0].Token.UserCode).Name,
                            node.Children[0].Token.UserCode));
                }
                else
                {
                    result.Type = VVarValue.VVarType.Decimal;
                    result.Value = decimal.Parse((string)result.Value);
                }
            }

            VVar tempVar;
            int i = 2;

            while (i < node.Children.Count)
            {
                tempVar = this.variables.GetVVar(node.Children[i].Token.UserCode);

                if (node.Children[i].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[i].Token.UserCode);
                }

                switch (tempVar.Value.Type)
                {
                    case VVarValue.VVarType.Decimal:
                        break;
                    case VVarValue.VVarType.String:
                        tempVar.Value.Value = decimal.Parse((string)tempVar.Value.Value);
                        tempVar.Value.Type = VVarValue.VVarType.Decimal;
                        break;
                    default:
                        throw new Exception(
                            string.Format(
                                "Wrong variable type for multiplicative expression. Variable: {0} with code: {1}",
                                this.variables.GetVVar(node.Children[i].Token.UserCode).Name,
                                node.Children[i].Token.UserCode));
                }

                int operatorCode = node.Children[i - 1].Token.Code;
                if (operatorCode == SystemTokens.GetCode("*"))
                {
                    result.Value = ((decimal)result.Value) * ((decimal)tempVar.Value.Value);
                }
                else if (operatorCode == SystemTokens.GetCode("/"))
                {
                    result.Value = ((decimal)result.Value) / ((decimal)tempVar.Value.Value);
                }
                else if (operatorCode == SystemTokens.GetCode("%"))
                {
                    result.Value = ((decimal)result.Value) % ((decimal)tempVar.Value.Value);
                }
                else
                {
                    throw new Exception(
                        string.Format("Wrong multiplicative operation with code {0}", node.Children[i - 1].Token.Code));
                }

                i += 2;
            }

            return result;
        }

        /// <summary>
        /// Executes the one value expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// Included value.
        /// </returns>
        private VVarValue ExecuteOneValueExpression(GrammarNode node)
        {
            // RULES:
            // Literal = <DECIMAL_LITERAL> | <STRING_LITERAL> | BoolenLiteral | NullLiteral ;
            // BoolenLiteral = "true" | "false" ;
            // NullLiteral = "null" ;
            // SourceElement = FunctionDeclaration | Statement ;

            if (node.Children.Count == 1)
            {
                var result = new VVarValue(this.variables.GetVVar(node.Children[0].Token.UserCode).Value);
                if (node.Children[0].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[0].Token.UserCode);
                }

                return result;
            }

            throw new InvalidOperationException("Wrong param node.");
        }

        /// <summary>
        /// Executes the postfix expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// </returns>
        private VVarValue ExecutePostfixExpression(GrammarNode node)
        {
            // RULE:
            // PostfixExpression = LeftHandSideExpression [ PostfixOperator ] ;
            // PostfixOperator = "++" | "--" ;
            if (node.Children.Count != 1 && node.Children.Count != 2)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            VVar variable = this.variables.GetVVar(node.Children[0].Token.UserCode);

            if (node.Children.Count == 2)
            {
                if (!variable.Assignable)
                {
                    throw new InvalidOperationException("Variable should be assignable.");
                }

                if (variable.Value.Type != VVarValue.VVarType.Decimal
                    && variable.Value.Type != VVarValue.VVarType.String)
                {
                    throw new InvalidOperationException("Wrong variable type.");
                }

                if (variable.Value.Type == VVarValue.VVarType.String)
                {
                    variable.Value = new VVarValue
                        {
                            Type = VVarValue.VVarType.Decimal,
                            Value = decimal.Parse(variable.Value.Value.ToString())
                        };
                }

                int operatorCode = node.Children[1].Token.Code;

                if (operatorCode == SystemTokens.GetCode("++"))
                {
                    variable.Value.Value = ((decimal)variable.Value.Value) + 1;
                }
                else if (operatorCode == SystemTokens.GetCode("--"))
                {
                    variable.Value.Value = ((decimal)variable.Value.Value) - 1;
                }
                else
                {
                    throw new InvalidOperationException("Wrong postfix operator.");
                }
            }

            return new VVarValue(variable.Value);
        }

        /// <summary>
        /// Executes the primary expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// Contained value.
        /// </returns>
        private VVarValue ExecutePrimaryExpression(GrammarNode node)
        {
            // RULE:
            // PrimaryExpression = "this" | ObjectLiteral | ( "(" Expression ")" ) | <IDENTIFIER> | ArrayLiteral | Literal ;
            VVarValue result;

            if (node.Children.Count == 3)
            {
                if (node.Children[0].Token.Code == SystemTokens.GetCode("(")
                    && node.Children[2].Token.Code == SystemTokens.GetCode(")"))
                {
                    result = new VVarValue(this.variables.GetVVar(node.Children[1].Token.UserCode).Value);
                    if (node.Children[1].Token.Code == SystemTokens.TempVar)
                    {
                        // Remove temp var.
                        this.variables.RemoveTempVar(node.Children[1].Token.UserCode);
                    }
                }
                else
                {
                    throw new Exception("Wrong brackets in Primary expression.");
                }
            }
            else if (node.Children.Count == 1)
            {
                if (node.Children[0].Token.Code == SystemTokens.GetCode("this"))
                {
                    throw new Exception("_this_ key word is not implemented yet.");
                }

                result = new VVarValue(this.variables.GetVVar(node.Children[0].Token.UserCode).Value);
                if (node.Children[0].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[0].Token.UserCode);
                }
            }
            else
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            return result;
        }

        /// <summary>
        /// Executes the program expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// Result of executing program.
        /// </returns>
        private VVarValue ExecuteProgramExpression(GrammarNode node)
        {
            // RULE:
            // Program = [ SourceElements ] <EOF> ;

            if (node.Children.Count == 2)
            {
                var result = new VVarValue(this.variables.GetVVar(node.Children[0].Token.UserCode).Value);
                if (node.Children[0].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[0].Token.UserCode);
                }

                if (node.Children[1].Value != "<EOF>")
                {
                    throw new Exception("Wrong end of file O_o.");
                }

                return result;
            }

            if (node.Children.Count == 1)
            {
                if (node.Children[0].Value != "<EOF>")
                {
                    throw new Exception("Wrong end of file O_o.");
                }

                return new VVarValue { Type = VVarValue.VVarType.Unknown };
            }

            throw new InvalidOperationException("Wrong param node.");
        }

        /// <summary>
        /// Executes the relational expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// </returns>
        private VVarValue ExecuteRelationalExpression(GrammarNode node)
        {
            // RULE:
            // [ ]RelationalExpression = ShiftExpression { RelationalOperator ShiftExpression } ;
            // [ ]RelationalOperator = "<" | ">" | "<=" | ">=" | "instanceof" | "in" ;
            // [ ]RelationalExpressionNoIn = ShiftExpression { RelationalNoInOperator ShiftExpression } ;
            // [ ]RelationalNoInOperator = "<" | ">" | "<=" | ">=" | "instanceof" ;
            if (node.Children.Count == 0 || node.Children.Count % 2 == 0)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            var result = new VVarValue(this.variables.GetVVar(node.Children[0].Token.UserCode).Value);

            if (node.Children[0].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[0].Token.UserCode);
            }

            VVarValue tempVarValue;
            int i = 2;

            while (i < node.Children.Count)
            {
                tempVarValue = new VVarValue(this.variables.GetVVar(node.Children[i].Token.UserCode).Value);

                if (node.Children[i].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[i].Token.UserCode);
                }

                int operatorCode = node.Children[i - 1].Token.Code;

                if (result.Type != VVarValue.VVarType.String && tempVarValue.Type != VVarValue.VVarType.String)
                {
                    bool wasException = false;
                    VVarValue a = new VVarValue { Type = VVarValue.VVarType.Decimal, Value = (decimal)0 },
                              b = new VVarValue { Type = VVarValue.VVarType.Decimal, Value = (decimal)0 };
                    try
                    {
                        a = this.GetTypedValue(result, VVarValue.VVarType.Decimal);
                        b = this.GetTypedValue(tempVarValue, VVarValue.VVarType.Decimal);
                    }
                    catch (Exception e)
                    {
                        wasException = true;
                    }

                    if (!wasException)
                    {
                        bool val;
                        if (operatorCode == SystemTokens.GetCode(">"))
                        {
                            val = ((decimal)a.Value) > ((decimal)b.Value);
                        }
                        else if (operatorCode == SystemTokens.GetCode("<"))
                        {
                            val = ((decimal)a.Value) < ((decimal)b.Value);
                        }
                        else if (operatorCode == SystemTokens.GetCode("<="))
                        {
                            val = ((decimal)a.Value) <= ((decimal)b.Value);
                        }
                        else if (operatorCode == SystemTokens.GetCode(">="))
                        {
                            val = ((decimal)a.Value) >= ((decimal)b.Value);
                        }
                        else if (operatorCode == SystemTokens.GetCode("instanceof"))
                        {
                            throw new NotImplementedException("'instanceof' operator isn't implemented yet");
                        }
                        else if (operatorCode == SystemTokens.GetCode("in"))
                        {
                            throw new NotImplementedException("'in' operator isn't implemented yet");
                        }
                        else
                        {
                            throw new Exception(
                                string.Format(
                                    "Wrong Relational operation with code {0}", node.Children[i - 1].Token.Code));
                        }

                        result = new VVarValue { Type = VVarValue.VVarType.Bool, Value = val };
                        i += 2;
                        continue;
                    }
                }

                result = this.GetTypedValue(result, VVarValue.VVarType.String);
                tempVarValue = this.GetTypedValue(tempVarValue, VVarValue.VVarType.String);

                bool val1;
                if (operatorCode == SystemTokens.GetCode(">"))
                {
                    val1 = string.CompareOrdinal((string)result.Value, (string)tempVarValue.Value) > 0;
                }
                else if (operatorCode == SystemTokens.GetCode("<"))
                {
                    val1 = string.CompareOrdinal((string)result.Value, (string)tempVarValue.Value) < 0;
                }
                else if (operatorCode == SystemTokens.GetCode("<="))
                {
                    val1 = string.CompareOrdinal((string)result.Value, (string)tempVarValue.Value) <= 0;
                }
                else if (operatorCode == SystemTokens.GetCode(">="))
                {
                    val1 = string.CompareOrdinal((string)result.Value, (string)tempVarValue.Value) >= 0;
                }
                else if (operatorCode == SystemTokens.GetCode("instanceof"))
                {
                    throw new NotImplementedException("'instanceof' operator isn't implemented yet");
                }
                else if (operatorCode == SystemTokens.GetCode("in"))
                {
                    throw new NotImplementedException("'in' operator isn't implemented yet");
                }
                else
                {
                    throw new Exception(
                        string.Format("Wrong Relational operation with code {0}", node.Children[i - 1].Token.Code));
                }

                result = new VVarValue { Type = VVarValue.VVarType.Bool, Value = val1 };

                i += 2;
            }

            return result;
        }

        /// <summary>
        /// Executes the variable declaration expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// Undefined value.
        /// </returns>
        private VVarValue ExecuteVariableDeclarationExpression(GrammarNode node)
        {
            // RULE:
            // VariableDeclaration = <IDENTIFIER> [ Initialiser ] ;
            // VariableDeclarationNoIn = <IDENTIFIER> [ InitialiserNoIn ] ;
            if (node.Children.Count == 0 || node.Children.Count > 2)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            VVarValue value;
            if (node.Children.Count == 1)
            {
                value = new VVarValue { Type = VVarValue.VVarType.Unknown };
            }
            else
            {
                value = new VVarValue(this.variables.GetVVar(node.Children[1].Token.UserCode).Value);
                if (node.Children[1].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[1].Token.UserCode);
                }
            }

            // Declare variable.
            this.variables.DeclareVariable(node.Children[0].Token.UserCode, this.userTokens, value);

            return new VVarValue { Type = VVarValue.VVarType.Unknown };
        }

        /// <summary>
        /// Executes the variable declaration list expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// Undefined value.
        /// </returns>
        private VVarValue ExecuteVariableDeclarationListExpression(GrammarNode node)
        {
            // RULE:
            // VariableDeclarationList = VariableDeclaration { "," VariableDeclaration } ;
            // VariableDeclarationListNoIn = VariableDeclarationNoIn { "," VariableDeclarationNoIn } ;
            if (node.Children.Count < 3)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            int i = 0;

            while (i < node.Children.Count)
            {
                if (i != 0 && node.Children[i - 1].Token.Code != SystemTokens.GetCode(","))
                {
                    throw new Exception("Wrong comma in variable declaration list");
                }

                if (node.Children[i].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[i].Token.UserCode);
                }
                else if (node.Children[i].Token.Code == SystemTokens.IdCode)
                {
                    // Declare variable.
                    this.variables.DeclareVariable(
                        node.Children[i].Token.UserCode,
                        this.userTokens,
                        new VVarValue { Type = VVarValue.VVarType.Unknown });
                }
                else
                {
                    throw new Exception("Wrong variable ID in variable statement.");
                }

                i += 2;
            }

            return new VVarValue { Type = VVarValue.VVarType.Unknown };
        }

        /// <summary>
        /// Executes the variable statement expression.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// Undefined value.
        /// </returns>
        private VVarValue ExecuteVariableStatementExpression(GrammarNode node)
        {
            // RULE:
            // VariableStatement = "var" VariableDeclarationList ";" ;
            if (node.Children.Count != 3)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            if (node.Children[0].Token.Code != SystemTokens.GetCode("var")
                && node.Children[2].Token.Code != SystemTokens.GetCode(";"))
            {
                throw new Exception("Wrong key word in variable statement.");
            }

            if (node.Children[1].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[1].Token.UserCode);
            }
            else if (node.Children[1].Token.Code == SystemTokens.IdCode)
            {
                // Declare variable.
                this.variables.DeclareVariable(
                    node.Children[1].Token.UserCode,
                    this.userTokens,
                    new VVarValue { Type = VVarValue.VVarType.Unknown });
            }
            else
            {
                throw new Exception("Wrong variable ID in variable statement.");
            }

            return new VVarValue { Type = VVarValue.VVarType.Unknown };
        }

        /// <summary>
        /// Gets the typed value.
        /// </summary>
        /// <param name="value">
        /// The value.
        /// </param>
        /// <param name="aimType">
        /// Type of the aim.
        /// </param>
        /// <returns>
        /// </returns>
        private VVarValue GetTypedValue(VVarValue value, VVarValue.VVarType aimType)
        {
            if (value.Type == aimType)
            {
                return new VVarValue(value);
            }

            switch (aimType)
            {
                case VVarValue.VVarType.Array:
                    throw new NotImplementedException("Not implemented parse to array.");
                case VVarValue.VVarType.Bool:
                    switch (value.Type)
                    {
                        case VVarValue.VVarType.Array:
                            throw new NotImplementedException("Not implemented parse from array.");
                        case VVarValue.VVarType.Decimal:
                            return new VVarValue { Value = ((decimal)value.Value) != 0, Type = VVarValue.VVarType.Bool };
                        case VVarValue.VVarType.Function:
                            return new VVarValue { Value = value.Value != null, Type = VVarValue.VVarType.Bool };
                        case VVarValue.VVarType.Object:
                            return new VVarValue { Value = value.Value != null, Type = VVarValue.VVarType.Bool };
                        case VVarValue.VVarType.String:
                            if (string.IsNullOrEmpty((string)value.Value))
                            {
                                return new VVarValue { Value = false, Type = VVarValue.VVarType.Bool };
                            }

                            return new VVarValue
                                {
                                    Value = bool.Parse((string)value.Value),
                                    Type = VVarValue.VVarType.Bool
                                };
                        case VVarValue.VVarType.Unknown:
                            return new VVarValue { Value = false, Type = VVarValue.VVarType.Bool };
                    }

                    break;
                case VVarValue.VVarType.Decimal:
                    switch (value.Type)
                    {
                        case VVarValue.VVarType.Array:
                            throw new NotImplementedException("Not implemented parse from array to decimal.");
                        case VVarValue.VVarType.Bool:
                            return new VVarValue
                                {
                                    Value = ((bool)value.Value) ? 1 : 0,
                                    Type = VVarValue.VVarType.Decimal
                                };
                        case VVarValue.VVarType.Function:
                            throw new NotImplementedException("Not implemented parse from function to decimal.");
                        case VVarValue.VVarType.Object:
                            throw new NotImplementedException("Not implemented parse from object to decimal.");
                        case VVarValue.VVarType.String:
                            return new VVarValue
                                {
                                    Value = decimal.Parse((string)value.Value),
                                    Type = VVarValue.VVarType.Decimal
                                };
                        case VVarValue.VVarType.Unknown:
                            throw new NotImplementedException("Not implemented parse from unknown to decimal.");
                    }

                    break;
                case VVarValue.VVarType.Function:
                    throw new NotImplementedException("Not implemented parse to function.");
                case VVarValue.VVarType.Object:
                    throw new NotImplementedException("Not implemented parse to object.");
                case VVarValue.VVarType.String:
                    return new VVarValue { Value = value.Value.ToString(), Type = VVarValue.VVarType.String };
                case VVarValue.VVarType.Unknown:
                    throw new Exception("Can't parse to unknown type");
            }

            return null;
        }

        /// <summary>
        /// Parses the grammar tree to tree which we can display in tree view control.
        /// </summary>
        /// <param name="tree">
        /// The tree.
        /// </param>
        /// <returns>
        /// Root of tree.
        /// </returns>
        private TreeNode ParseTree(GrammarNode tree)
        {
            var node = new TreeNode();

            if (tree.Token == null)
            {
                node.Text = tree.Value;
                foreach (GrammarNode child in tree.Children)
                {
                    node.Nodes.Add(this.ParseTree(child));
                }
            }
            else
            {
                if (tree.Token.Code == SystemTokens.NumericLiteralCode
                    || tree.Token.Code == SystemTokens.BoolLiteralCode || tree.Token.Code == SystemTokens.NullLiteral
                    || tree.Token.Code == SystemTokens.StringLiteralCode || tree.Token.Code == SystemTokens.TempVar)
                {
                    node.Text = this.variables.GetVVar(tree.Token.UserCode).Name;
                }
                else if (tree.Token.Code == SystemTokens.IdCode)
                {
                    node.Text = this.userTokens.GetByUserCode(tree.Token.UserCode);
                }
                else
                {
                    node.Text = SystemTokens.GetName(tree.Token.Code);
                }
            }

            return node;
        }

        /// <summary>
        /// Checks that node is prepare to execute.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// Child that should be calculating before.
        /// </returns>
        private GrammarNode checkNode(GrammarNode node)
        {
            foreach (GrammarNode child in node.Children)
            {
                if (child.Token == null && child.Value != "<EOF>")
                {
                    return child;
                }
            }

            return null;
        }

        /// <summary>
        /// Tries the execute node.
        /// </summary>
        /// <param name="node">
        /// The node.
        /// </param>
        /// <returns>
        /// True if no errors; otherwise false.
        /// </returns>
        private bool tryExecuteNode(GrammarNode node)
        {
            VVarValue result;
            try
            {
                // Select correct function.
                switch (node.Value)
                {
                    case "AdditiveExpression [CURRENT NODE]":
                        result = this.ExecuteAdditiveExpression(node);
                        break;
                    case "MultiplicativeExpression [CURRENT NODE]":
                        result = this.ExecuteMultiplicativeExpression(node);
                        break;
                    case "VariableDeclaration [CURRENT NODE]":
                    case "VariableDeclarationNoIn [CURRENT NODE]":
                        result = this.ExecuteVariableDeclarationExpression(node);
                        break;
                    case "Initialiser [CURRENT NODE]":
                    case "InitialiserNoIn [CURRENT NODE]":
                        result = this.ExecuteInitialiserExpression(node);
                        break;
                    case "VariableStatement [CURRENT NODE]":
                        result = this.ExecuteVariableStatementExpression(node);
                        break;
                    case "VariableDeclarationList [CURRENT NODE]":
                    case "VariableDeclarationListNoIn [CURRENT NODE]":
                        result = this.ExecuteVariableDeclarationListExpression(node);
                        break;
                    case "AssignmentExpression [CURRENT NODE]":
                    case "AssignmentExpressionNoIn [CURRENT NODE]":
                        result = this.ExecuteAssignmentExpression(node);
                        break;
                    case "PrimaryExpression [CURRENT NODE]":
                        result = this.ExecutePrimaryExpression(node);
                        break;
                    case "Literal [CURRENT NODE]":
                    case "NullLiteral [CURRENT NODE]":
                    case "SourceElement [CURRENT NODE]":
                    case "Statement [CURRENT NODE]":
                    case "IterationStatement [CURRENT NODE]":
                        result = this.ExecuteOneValueExpression(node);
                        break;
                    case "SourceElements [CURRENT NODE]":
                    case "StatementList [CURRENT NODE]":
                        result = this.ExecuteListExpression(node);
                        break;
                    case "EmptyStatement [CURRENT NODE]":
                        result = this.ExecuteEmptyStatementExpression(node);
                        break;
                    case "Program [CURRENT NODE]":
                        result = this.ExecuteProgramExpression(node);
                        this.logs.AppendLine("Program was executed successful.");
                        this.IsExecuted = true;
                        break;
                    case "ExpressionStatement [CURRENT NODE]":
                        result = this.ExecuteExpressionStatementExpression(node);
                        break;
                    case "PostfixExpression [CURRENT NODE]":
                        result = this.ExecutePostfixExpression(node);
                        break;
                    case "BitwiseANDExpression [CURRENT NODE]":
                    case "BitwiseORExpression [CURRENT NODE]":
                    case "BitwiseXORExpression [CURRENT NODE]":
                        result = this.ExecuteBitwiseExpression(node);
                        break;
                    case "LogicalANDExpression [CURRENT NODE]":
                    case "LogicalORExpression [CURRENT NODE]":
                        result = this.ExecuteLogicalExpression(node);
                        break;
                    case "RelationalExpression [CURRENT NODE]":
                    case "RelationalExpressionNoIn [CURRENT NODE]":
                        result = this.ExecuteRelationalExpression(node);
                        break;
                    case "ConditionalExpression [CURRENT NODE]":
                    case "ConditionalExpressionNoIn [CURRENT NODE]":
                        result = this.ExecuteConditionalExpression(node);
                        break;
                    case "EqualityExpression [CURRENT NODE]":
                    case "EqualityExpressionNoIn [CURRENT NODE]":
                        result = this.ExecuteEqualityExpression(node);
                        break;
                    case "IfStatement [CURRENT NODE]":
                        result = this.ExecuteIfStatementExpresion(node);
                        break;
                    case "WhileStatement [CURRENT NODE]":
                        result = this.ExecuteWhileExpresion(node);
                        break;
                    case "Block [CURRENT NODE]":
                        result = this.ExecuteBlockExpression(node);
                        break;
                    case "Expression [CURRENT NODE]":
                    case "ExpressionNoIn [CURRENT NODE]":
                        result = this.ExecuteExpressionExpression(node);
                        break;
                    case "For2Statement [CURRENT NODE]":
                        result = this.ExecuteFor2Expresion(node);
                        break;
                    case "<EOF> [CURRENT NODE]":
                        throw new Exception("We shouldn't be here.");
                    default:
                        throw new NotImplementedException("This operation is not implemented yet.");
                }
            }
            catch (Exception e)
            {
                this.logs.AppendLine(string.Format("Fail. {0}", e.Message));
                return false;
            }

            node.Children.Clear();
            node.Token = new Token(SystemTokens.TempVar, this.variables.TempVar(result));

            return true;
        }

        /// <summary>
        /// Executes the while expresion.
        /// </summary>
        /// <param name="node">The node.</param>
        /// <returns></returns>
        private VVarValue ExecuteWhileExpresion(GrammarNode node)
        {
            // RULE:
            // WhileStatement = "while" "(" Expression ")" Statement ;
            if (node.Children.Count != 5)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            if (node.Children[2].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[2].Token.UserCode);
            }

            VVarValue result;

            if (node.Children[4].Token != null)
            {
                result = new VVarValue(this.variables.GetVVar(node.Children[4].Token.UserCode).Value);
                if (node.Children[4].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[4].Token.UserCode);
                }
            }
            else
            {
                result = new VVarValue { Type = VVarValue.VVarType.Unknown };
            }

            return result;
        }

        private VVarValue ExecuteFor2Expresion(GrammarNode node)
        {
            // RULE:
            // For2Statement = "for" "(" "var" VariableDeclarationList ";" Expression ";" Expression ")" Statement ;
            if (node.Children.Count != 10)
            {
                throw new InvalidOperationException("Wrong param node.");
            }

            if (node.Children[3].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[3].Token.UserCode);
            }

            if (node.Children[5].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[5].Token.UserCode);
            }

            if (node.Children[7].Token != null && node.Children[7].Token.Code == SystemTokens.TempVar)
            {
                // Remove temp var.
                this.variables.RemoveTempVar(node.Children[7].Token.UserCode);
            }

            VVarValue result;

            if (node.Children[9].Token != null)
            {
                result = new VVarValue(this.variables.GetVVar(node.Children[4].Token.UserCode).Value);
                if (node.Children[9].Token.Code == SystemTokens.TempVar)
                {
                    // Remove temp var.
                    this.variables.RemoveTempVar(node.Children[4].Token.UserCode);
                }
            }
            else
            {
                result = new VVarValue { Type = VVarValue.VVarType.Unknown };
            }

            return result;
        }

        #endregion
    }
}